﻿using FoftmAging.Core;
using Ice.Extension;
using IoTClient;
using IoTClient.Clients.Modbus;
using IoTClient.Common.Helpers;
using Polly;
using ScottPlot.Colormaps;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Configuration;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FoftmAging
{
    public partial class AgingControl : UserControl
    {

        private GroupSetting _setting;
        private Config _config;
        public GroupSetting Setting { private get => _setting; set => _setting = value; }

        public event Action<int, string> OnMessage;

        private ModbusRtuClient _client;
        public ModbusRtuClient Client { get => _client; }

        private CancellationTokenSource _tokenSource;
        private StringBuilder _sb = new StringBuilder();
        private List<SensorData> _sensorDatas = new List<SensorData>();

        public AgingControl()
        {
            InitializeComponent();
            _config = IniHelper.GetConfig();
        }


        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            for (int i = 0; i < _setting.ChannelCount; i++)
            {
                _sensorDatas.Add(new SensorData
                {
                    Id = (byte)(i + 1)
                });

                dataGridView1.Rows.Add(i + 1, "xxx.x", "xxx", "xxx");
            }
            dataGridView1.CurrentCell = null;

            dataGridView1.Columns[4].ReadOnly = false;
        }

        /// <summary>
        /// 初始化客户端
        /// </summary>
        public void OpenClient()
        {
            if (_client == null)
            {
                try
                {
                    _client = new ModbusRtuClient(_setting.PortName, _config.BaudRate, 8, StopBits.One, Parity.None, 60);
                    _client.Open();
                }
                catch (Exception ex)
                {

                    ShowInfo(ex.Message);
                    return;
                }
            }
        }


        public void Start()
        {
            _tokenSource = new CancellationTokenSource();
            Task.Factory.StartNew(CollectData, null, TaskCreationOptions.LongRunning);
        }


        public void Stop()
        {
            WriteLog(_sb.ToString());
            _tokenSource?.Cancel();
        }

        public void CloseClient()
        {
            _client?.Close();
            _client = null;
            ShowInfo("老化完成");
        }

        /// <summary>
        /// 默认设置通道1 的通道id
        /// </summary>
        /// <param name="channelId"></param>
        public void SetChannels(byte channelId)
        {
            //ShowInfo("设置通道中");
            //foreach (var item in _sensorDatas)
            //{
            //    ShowInfo($"设置通道{item.Id}");
            //    var bytes = new byte[5]{
            //        (byte)1,0x65,00,01,(byte)item.Id};
            //    var commandBytes = CRC16.GetCRC16(bytes);
            //    _client.SendPackageReliable(commandBytes);
            //    Thread.Sleep(100);
            //}
            if (channelId > _setting.ChannelCount) return;
            ShowInfo($"设置通道{channelId}");
            for (int k = 1; k <= 32; k++)  //1-40 ip
            {
                var bytes = new byte[5] { 0, 0x65, 00, 01, channelId };
                bytes[0] = (byte)k;
                var commandBytes = CRC16.GetCRC16(bytes);
                var result = _client.SendPackageReliable(commandBytes);
                //WriteLog($"{_setting.GroupNo}Result: {result.IsSucceed}:{k}->{BitConverter.ToString(bytes)} | {BitConverter.ToString(commandBytes)} {BitConverter.ToString(result.Value)} -> {result.TimeConsuming}");
                //if (result.IsSucceed && result.TimeConsuming.HasValue && result.TimeConsuming < 60)  //用时小于 60毫秒
                //{
                //    return;
                //}
            }
        }

        public void ResetChannels(byte channelId)
        {
            if (!_config.IsResetChannel) return;
            if (channelId > _setting.ChannelCount) return;
            ShowInfo($"还原通道{channelId}");
            //foreach (var item in _sensorDatas)
            //{
            //    ShowInfo($"还原通道{item.Id}");
            //    var bytes = new byte[5]{
            //        (byte)item.Id,0x65,00,01,(byte)1};
            //    var commandBytes = CRC16.GetCRC16(bytes);
            //    _client.SendPackageReliable(commandBytes);
            //    Thread.Sleep(100);
            //}

            var bytes = new byte[5]{
                    channelId,0x65,00,01,(byte)1};
            var commandBytes = CRC16.GetCRC16(bytes);
            _client.SendPackageReliable(commandBytes);
        }

        private void ShowInfo(string info)
        {
            lblShow.ShowInfo(info);
            OnMessage?.Invoke(_setting.GroupNo, $"{_setting.GroupNo}> " + info);

        }

        private void CollectData(object boj)
        {
            ShowInfo("老化中");
            var list = new List<TimeTemperature>();
            while (!_tokenSource.Token.IsCancellationRequested)
            {
                list.Clear();
                var now = DateTime.Now;
                for (int i = 0; i < _sensorDatas.Count; i++)
                {
                    var sensorData = _sensorDatas[i];
                    var timeTemperature = new TimeTemperature()
                    {
                        ChannelNo = sensorData.Id,
                        Time = now
                    };
                    try
                    {

                        var value = Policy.HandleResult<Result<ushort>>(x => !x.IsSucceed).Retry(3)
                            .Execute(() => _client.ReadUInt16("7", sensorData.Id));
                        if (value.IsSucceed)
                        {
                            var temperatureValue = (value.Value - 2732) * 1.0 / 10;
                            sensorData.Temperature = temperatureValue;
                            //温度
                            timeTemperature.Temperature = temperatureValue;
                            list.Add(timeTemperature);
                        }
                        else
                        {
                            sensorData.Temperature = null;
                        }
                        Thread.Sleep(50); //间隔读取时间

                        var result = Policy.HandleResult<Result<ushort>>(x => !x.IsSucceed).Retry(3)
                            .Execute(() => _client.ReadUInt16("6", sensorData.Id));
                        if (result.IsSucceed)
                        {
                            var bytes = BitConverter.GetBytes(result.Value);
                            sensorData.LightIntensity = bytes[1];
                            sensorData.Signal = bytes[0];
                        }
                        else
                        {
                            sensorData.LightIntensity = null;
                            sensorData.Signal = null;
                        }
                        UpdateRow(sensorData); //更新行
                        _sb.AppendLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} CH {i + 1} ID:{sensorData.Id} " +
                            $"温度：{sensorData.Temperature?.ToString("f2")} 信号：{sensorData.Signal} 光强：{sensorData.LightIntensity}");
                    }
                    catch (Exception ex)
                    {
                        sensorData.Temperature = null;
                        sensorData.Signal = null;
                        sensorData.LightIntensity = null;
                        UpdateRow(sensorData); //更新行
                    }
                }
                try
                {
                    SaveData(list);
                }
                catch (Exception ex)
                {
                    File.WriteAllText($"{_setting.GroupNo}-error.txt", ex.StackTrace);
                }
                Thread.Sleep(_config.IntervalMillisecond);

            }
        }

        private void UpdateRow(SensorData data)
        {
            var rowIdx = data.Id - 1;
            dataGridView1[1, rowIdx].Value = data.Temperature.HasValue ? data.Temperature.Value.ToString("f1") : "XXX.X";
            dataGridView1[2, rowIdx].Value = data.Signal.HasValue ? data.Signal.Value.ToString() : "XXX";
            dataGridView1[3, rowIdx].Value = data.LightIntensity.HasValue ? data.LightIntensity.Value.ToString() : "XXX";

            if (data.Temperature.HasValue && (data.Temperature.Value < _config.MinTemperature || data.Temperature > _config.MaxTemperature))
            {
                dataGridView1.Rows[rowIdx].DefaultCellStyle.ForeColor = Color.Red;
            }
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="timeTemperatures"></param>
        private void SaveData(List<TimeTemperature> timeTemperatures)
        {
            if (!timeTemperatures.Any()) return;
            var dir = Path.Combine("datas", _setting.GroupNo.ToString());
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = $"{DateTime.Now:yyyy-MM-dd}.csv";
            filename = Path.Combine(dir, filename);
            var lines = new List<string>();
            foreach (var item in timeTemperatures)
            {
                lines.Add($"{item.ChannelNo},{item.Temperature},{item.Time:yyyy-MM-dd HH:mm:ss}");
            }
            File.AppendAllLines(filename, lines);
        }

        private void WriteLog(string log)
        {
            var dir = Path.Combine("logs", _setting.GroupNo.ToString() + "组");
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            File.WriteAllText(Path.Combine(dir, $"{DateTime.Now:yyyyMMddHHmmss}.txt"), log);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            new HistoryChartForm() { Setting = _setting }.ShowDialog();
        }

        private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0 && e.ColumnIndex == 4)
            {

                var valueStr = dataGridView1.CurrentCell.Value?.ToString();
                if (!double.TryParse(valueStr, out var value))
                {
                    return;
                }

                int tempDeviation = 0;
                if (value > 0)
                {
                    tempDeviation = (int)(100 + (value * 10));
                }
                else
                {
                    tempDeviation = (int)(100 + (value * 10));
                }



                var channel = int.Parse(dataGridView1[0, e.RowIndex].Value.ToString());
                var bytes = new byte[5]
                {
                    (byte)channel,0x65,01,01,(byte)tempDeviation
                };
                var commandBytes = CRC16.GetCRC16(bytes);
                _client.SendPackageReliable(commandBytes);
            }
        }

        /// <summary>
        /// 重置通道id
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnResetChannelIds_Click(object sender, EventArgs e)
        {
            bool b = MessageBox.Show("您是否确定重置该组全部通道ID", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes;
            if (!b) return;
            btnResetChannelIds.Enabled = false;
            try
            {
                await Task.Run(() =>
                {
                    for (int i = _setting.ChannelCount; i > 0; i--)
                    {
                        ShowInfo($"正在重置通道：{i} ID");
                        var bytes = new byte[5]{
                    (byte)i,0x65,00,01,(byte)1};
                        var commandBytes = CRC16.GetCRC16(bytes);
                        _client.SendPackageReliable(commandBytes);
                    }
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                ShowInfo("重置通道ID完成");
                btnResetChannelIds.Enabled = true;
            }
        }
    }
}
